home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / graphics / geodome1.zip / geodome.c next >
C/C++ Source or Header  |  1994-04-28  |  9KB  |  412 lines

  1. #include <math.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. #define TRIANGLE     1
  7. #define MESH        2
  8. #define ERROR         -1
  9. #define VERSION        1
  10. #define INCREMENT    1
  11. #define EMAIL_ADDRESS    "abw@oasis.icl.co.uk"
  12.  
  13.  
  14. /* 
  15.  * geodome.c 
  16.  * 
  17.  * (C) 1994 Andy Wardley (abw@oasis.icl.co.uk).  All Rights Reserved.
  18.  *
  19.  * maths libraray is required.
  20.  * getopt must be provided.
  21.  * 
  22.  */ 
  23.  
  24.  
  25. struct vertex { double x, y, z; };
  26. struct triangle { struct vertex a, b, c; };
  27.  
  28. struct edge 
  29.     struct vertex a, b; 
  30.     struct edge *next;
  31. };
  32.  
  33. struct joint
  34. {
  35.     struct vertex v;
  36.     struct joint *next;
  37. };
  38.  
  39.  
  40. /* default options */
  41. int mode = TRIANGLE;
  42. int rec_depth = 3;
  43. double pipe_radius = 0.01;
  44. double joint_radius = 0.015;
  45. double geodome_radius = 1;
  46.  
  47.  
  48. /* heads of linked lists */
  49. struct edge *first_edge;
  50. struct joint *first_joint;
  51.  
  52.  
  53. /* print usage message */
  54. void usage(void)
  55. {
  56.     printf("GEODOME V%d.%d     Geodome generator for POV-Ray V2.n      23-01-94\n", VERSION, INCREMENT);
  57.     printf("(C) 1994 Andy Wardley <%s>.  All Rights Reserved\n\n", EMAIL_ADDRESS);
  58.     printf("usage:\n\tgeodome [-r depth] [-t | -m [-p radius] [-j radius]]\n\n");
  59.     printf("\t-r depth      recursion depth (default: %i)\n", rec_depth);
  60.     printf("\t-t            generate triangles (default)\n");
  61.     printf("\t-m            generate pipe mesh\n");
  62.     printf("\t-p radius     pipe radius (mesh only) (default: %5.4f)\n", pipe_radius);
  63.     printf("\t-j radius     joint radius (mesh only) (default: %5.4f)\n", joint_radius);
  64.     printf("\nGEODOME may be freely distributed provided it is in its\n");
  65.     printf("original form and has not been modified in any way.\n");
  66. }
  67.  
  68.  
  69. char *basename(char *pathname)
  70. {
  71.     char *ptr;
  72.  
  73.     if ((ptr = strrchr(pathname, '\\')) != NULL)
  74.         return ptr + 1;
  75.     else
  76.         return NULL;
  77. }
  78.  
  79.  
  80.  
  81. /* add a joint to the linked list */
  82. int add_joint(struct vertex *v)
  83. {
  84.     struct joint *new_joint, *j;
  85.     
  86.     /* allocate memory for a new joint */
  87.     if ((new_joint = (struct joint *) malloc (sizeof(struct joint)))
  88.         == (struct joint *) NULL)
  89.     {
  90.         fprintf(stderr, "Out of memory\n");
  91.         return 1;
  92.     }
  93.  
  94.     /* load values and set fwd pointer to NULL */
  95.     new_joint->v = *v;
  96.     new_joint->next = (struct joint *) NULL;
  97.     
  98.     /* check for an empty list */
  99.     if (first_joint == (struct joint *) NULL)
  100.         first_joint = new_joint;
  101.     else
  102.     {
  103.         j = first_joint;
  104.  
  105.         /* traverse existing linked list */
  106.         for (;;)
  107.         {
  108.             /* forget duplicates */
  109.             if (memcmp(&j->v, &new_joint->v, sizeof(struct vertex)) == 0)
  110.             {
  111.                 free(new_joint);
  112.                 return 0;
  113.             }
  114.  
  115.             /* if at end of list, add new joint */
  116.             if (j->next == (struct joint *) NULL)
  117.             {
  118.                 j->next = new_joint;
  119.                 return 0;
  120.             }
  121.  
  122.             /* next list element */
  123.             j = j->next;            
  124.         }
  125.     }
  126.         
  127.     return 0;
  128. }
  129.  
  130.  
  131. /* add an edge to the linked list */
  132. int add_edge(struct vertex *a, struct vertex *b)
  133. {
  134.     struct edge *new_edge, *e;
  135.     
  136.     /* allocate memory for a new joint */
  137.     if ((new_edge = (struct edge *) malloc(sizeof(struct edge)))
  138.         == (struct edge *) NULL)
  139.     {
  140.         fprintf(stderr, "Out of memory\n");
  141.         return 1;
  142.     }
  143.  
  144.     /*
  145.     load the new structure with the data.  We always make sure that 
  146.     new_edge->a gets the smaller value (reason given below)
  147.     */ 
  148.     if (memcmp(a, b, sizeof(struct vertex)) < 0)
  149.     {
  150.         new_edge->a = *a;
  151.         new_edge->b = *b;
  152.     }
  153.     else
  154.     {
  155.         new_edge->a = *b;
  156.         new_edge->b = *a;
  157.     }
  158.  
  159.     /* set fwd pointer to NULL */
  160.     new_edge->next = (struct edge *) NULL;
  161.     
  162.     /* check for an empty linked list */
  163.     if (first_edge == (struct edge *) NULL)
  164.         first_edge = new_edge;
  165.     else
  166.     {
  167.         e = first_edge;
  168.  
  169.         /* traverse existing linked list */
  170.         for (;;)
  171.         {
  172.             /*
  173.             here we compare new element against existing
  174.             list elements.  If we find a match, we don't
  175.             need to add it again.  This is why we always
  176.             put the smallest value in a, otherwise, we   
  177.                wouldn't find the match if the ends were swapped.  
  178.             */
  179.             if (memcmp(&e->a, &new_edge->a, sizeof(struct vertex)) == 0
  180.                 && memcmp(&e->b, &new_edge->b, sizeof(struct vertex)) == 0)
  181.             {
  182.                 free(new_edge);
  183.                 return 0;
  184.             }
  185.  
  186.             /* add the edge if we've got to the end of the list */
  187.             if (e->next == (struct edge *) NULL)
  188.             {
  189.                 e->next = new_edge;
  190.                 return 0;
  191.             }
  192.  
  193.             /* next list item */
  194.             e = e->next;            
  195.         }
  196.     }
  197.         
  198.     return 0;
  199. }
  200.  
  201.  
  202. /* add the three joints and edges for a given triangle */
  203. int add_triangle(struct triangle *t)
  204. {
  205.     if (add_joint(&t->a) != 0)
  206.         return ERROR;
  207.     if (add_joint(&t->b) != 0)
  208.         return ERROR;
  209.     if (add_joint(&t->c) != 0)
  210.         return ERROR;
  211.     if (add_edge(&t->a, &t->b) != 0)
  212.         return ERROR;
  213.     if (add_edge(&t->b, &t->c) != 0)
  214.         return ERROR;
  215.     if (add_edge(&t->c, &t->a) != 0)
  216.         return ERROR;
  217. }
  218.  
  219.  
  220. /* returns the mid-point of two vertices (extended to geodome radius) */
  221. struct vertex average(struct vertex *v1, struct vertex *v2)
  222. {
  223.     struct vertex m;
  224.     double hypot, ratio;
  225.  
  226.     m.x = (v1->x + v2->x) / 2;
  227.     m.y = (v1->y + v2->y) / 2;
  228.     m.z = (v1->z + v2->z) / 2;
  229.  
  230.     hypot = sqrt(pow(m.x, 2) + pow(m.y, 2) + pow(m.z, 2));
  231.     ratio = geodome_radius / hypot;
  232.  
  233.     m.x *= ratio;
  234.     m.y *= ratio;
  235.     m.z *= ratio;
  236.  
  237.     return m;
  238. }
  239.  
  240.  
  241. /* sub-divide a triangle into 4 smaller triangles */
  242. void divide_triangle(struct triangle *t, int depth)
  243. {
  244.     struct triangle new_t[4];
  245.     int subt;
  246.  
  247.     new_t[0].a = t->a;
  248.     new_t[1].b = t->b;
  249.     new_t[2].c = t->c;
  250.  
  251.     new_t[0].c = new_t[2].a = new_t[3].b = average(&(t->a), &t->c);
  252.     new_t[0].b = new_t[1].a = new_t[3].c = average(&t->a, &t->b);
  253.     new_t[1].c = new_t[2].b = new_t[3].a = average(&t->c, &t->b);
  254.  
  255.     /* recurse if depth not yet reached */
  256.     if (--depth != 0)
  257.         for(subt = 0; subt < 4; subt++)
  258.             divide_triangle(&new_t[subt], depth);
  259.     else
  260.     {
  261.         /* 
  262.         dump triangle data or add to linked lists, depending
  263.         on the type of geodome
  264.         */
  265.         for(subt = 0; subt < 4; subt++)
  266.         {
  267.             if (mode == TRIANGLE)
  268.                 printf("\ttriangle {\n\t\t<%.10f, %.10f, %.10f>\
  269. \n\t\t<%.10f, %.10f, %.10f>\n\t\t<%.10f, %.10f, %.10f>\n\t}\n",
  270.                     new_t[subt].a.x, new_t[subt].a.y, new_t[subt].a.z, 
  271.                     new_t[subt].b.x, new_t[subt].b.y, new_t[subt].b.z, 
  272.                     new_t[subt].c.x, new_t[subt].c.y, new_t[subt].c.z);
  273.             else
  274.                 add_triangle(&new_t[subt]);
  275.         }
  276.     }
  277. }
  278.  
  279.  
  280.  
  281. void main(int argc, char **argv)
  282. {
  283.     char ch;
  284.     struct triangle t;
  285.     struct joint *j;
  286.     struct edge *e;
  287.  
  288.     /* zero linked list */
  289.     first_edge = NULL;
  290.     first_joint = NULL;
  291.     
  292.     /* read command line */
  293.     while ((ch = getopt(argc, argv, "tmr:p:j:")) != EOF)
  294.     {
  295.         switch(ch)
  296.         {
  297.             case 't':
  298.                 mode = TRIANGLE;
  299.                 break;
  300.  
  301.             case 'm':
  302.                 mode = MESH;
  303.                 break;
  304.  
  305.             case 'r':
  306.                 rec_depth = atoi(optarg);
  307.                 if (rec_depth == 0)
  308.                 {
  309.                     fprintf(stderr, "%s: invalid recursion depth\n",
  310.                              basename(argv[0]));
  311.                     exit(1);
  312.                 }
  313.                 break;
  314.  
  315.             case 'p':
  316.                 pipe_radius = atof(optarg);
  317.                 if (pipe_radius == 0)
  318.                 {
  319.                     fprintf(stderr, "%s: invalid pipe radius\n",
  320.                              basename(argv[0]));
  321.                     exit(1);
  322.                 }
  323.                 break;
  324.  
  325.             case 'j':
  326.                 joint_radius = atof(optarg);
  327.                 if (joint_radius == 0)
  328.                 {
  329.                     fprintf(stderr, "%s: invalid joint radius\n",
  330.                              basename(argv[0]));
  331.                     exit(1);
  332.                 }
  333.                 break;
  334.  
  335.             case '?':
  336.                 usage();
  337.                 exit(1);
  338.                 break;
  339.         }
  340.     }
  341.  
  342.     /* setup the parent triangle */
  343.     t.a.x = t.b.x = 0;
  344.     t.b.y = t.c.y = 0;
  345.     t.a.z = t.c.z = 0;
  346.     t.c.x = geodome_radius;
  347.     t.a.y = geodome_radius;
  348.     t.b.z = geodome_radius;
  349.  
  350.     /* print some stats */
  351.     fprintf(stderr, "recursion depth: %i\n", rec_depth);
  352.     fprintf(stderr, "           mode: %s\n", mode == TRIANGLE ? "triangles" : "mesh");
  353.     if (mode == MESH)
  354.     {
  355.         fprintf(stderr, "    pipe radius: %5.4f\n", pipe_radius);
  356.         fprintf(stderr, "   joint radius: %5.4f\n", joint_radius);
  357.     }
  358.         
  359.  
  360.     printf("/* model data created by geodome V%d.%d  */\n", VERSION, INCREMENT);
  361.     printf("/* by Andy Wardley <%s> */\n\n", EMAIL_ADDRESS);
  362.     printf("#declare geodome_eighth =\nunion {\n");
  363.     divide_triangle(&t, rec_depth);
  364.  
  365.     if (mode == MESH)
  366.     {
  367.         printf("//\tjoints\n");
  368.  
  369.         /* traverse joint list, printing and free as we go */
  370.         while (first_joint != (struct joint *) NULL)
  371.         {
  372.             j = first_joint;
  373.             first_joint = first_joint->next;
  374.             printf("\tsphere { <%.10f, %.10f, %.10f> %5.4f }\n", 
  375.                 j->v.x, j->v.y, j->v.z, joint_radius);
  376.             free(j);
  377.         }
  378.  
  379.         printf("\n//\tedges\n");
  380.  
  381.         /* traverse edge list, printing and freeing as we go */
  382.         while (first_edge != (struct edge *) NULL)
  383.         {
  384.             e = first_edge;
  385.             first_edge = first_edge->next;
  386.             printf("\tcone {\n");
  387.             printf("\t\t<%.10f, %.10f, %.10f> %5.4f\n", 
  388.                 e->a.x, e->a.y, e->a.z, pipe_radius);
  389.             printf("\t\t<%.10f, %.10f, %.10f> %5.4f\n\t}\n", 
  390.                 e->b.x, e->b.y, e->b.z, pipe_radius);
  391.             free(e);
  392.         }
  393.     }
  394.     
  395.     printf("}\n");
  396.  
  397.     /* finally create some complete geodome hemispheres and spheres */
  398.     printf("\n\n#declare geodome_hemisphere = \nunion {\n");
  399.     printf("\tobject { geodome_eighth }\n");
  400.     printf("\tobject { geodome_eighth rotate <0, 90, 0> }\n");
  401.     printf("\tobject { geodome_eighth rotate <0, 180, 0> }\n");
  402.     printf("\tobject { geodome_eighth rotate <0, 270, 0> }\n");
  403.     printf("}\n");
  404.     
  405.     printf("\n\n#declare geodome = \nunion {\n");
  406.     printf("\tobject { geodome_hemisphere }\n");
  407.     printf("\tobject { geodome_hemisphere rotate <180, 0, 0> }\n");
  408.     printf("}\n");
  409. }
  410.  
  411.